﻿#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;
using System.Threading.Tasks;
using BitwiseOre.IO;
using BitwiseOre.SharedMemory;
using BitwiseOre.SharedMemory.Core;
using BitwiseOre.SharedMemory.Utils;
using Moq;
using NUnit.Framework;

namespace BitwiseOre.Tests.SharedMemory
{
    [TestFixture]
    public sealed class SharedMemoryListenerFixture : AssertionHelper
    {
        [Test(Description = "Checks that disposing of the listener delgates to the disposer.")]
        public void Dispose_DelegatesToDisposer()
        {
            var disposer = new Mock<IDisposer<SharedMemoryListener>>();
            new SharedMemoryListener(disposer.Object, null, null, null, null).Dispose();

            disposer.Verify(d => d.Dispose(), "Disposal did not delegate to the disposer.");
        }

        [Test(Description = "Checks that begining an accpet operation delegates to the listener accept")]
        public void BeginAccept_DelegatesToInternalListenerAccept()
        {
            var internallistener = new Mock<IAcceptor>();
            internallistener.Setup(l => l.Accept(It.IsAny<TimeSpan>(), It.IsAny<Func<Guid, SharedMemoryStream>>()))
                .Returns(Task<SharedMemoryStream>.Factory.StartNew(() => null));
            Func<Guid, SharedMemoryStream> streamfactory = _ => null;
            var listener = new SharedMemoryListener(new Mock<IDisposer<SharedMemoryListener>>().Object,
                                                    internallistener.Object, streamfactory, null, null);
            var timespan = TimeSpan.FromMinutes(1);

            listener.AcceptTimeout = (int) timespan.TotalMilliseconds;
            listener.BeginAccept(null, null);

            internallistener.Verify(l => l.Accept(It.Is<TimeSpan>(t => t == timespan),
                                                  It.Is<Func<Guid, SharedMemoryStream>>(f => f == streamfactory)));
        }

        [Test(Description = "Checks that ending an accept operation delagates to the async result ender")]
        public void EndAccept_DelegatesToAsyncResultEnder()
        {
            var ender = new Mock<IAsyncResultEnder<SharedMemoryStream>>();
            var listener = new SharedMemoryListener(new Mock<IDisposer<SharedMemoryListener>>().Object,
                                                   new Mock<IAcceptor>().Object, _ => null, ender.Object, null);
            var task = Task.Factory.StartNew(() => (DisconnectableStream) null);

            listener.EndAccept(task);

            ender.Verify(e => e.EndTask(It.Is<IAsyncResult>(r => r == task),
                                        It.IsAny<Func<AggregateException, Exception>>()),
                         "Ending an accept operation did not delgate to the async result ender.");
        }

        [Test(Description = "Checks that begining a wait for operations delegates to the listener wait for")]
        public void BeginWaitFor_DelegatesToInternalListenerWaitFor()
        {
            var internallistener = new Mock<IAcceptor>();
            internallistener.Setup(l => l.WaitFor(It.IsAny<TimeSpan>()))
                .Returns(Task.Factory.StartNew(() => { }));
            var timespan = TimeSpan.FromMinutes(1);

            var listener = new SharedMemoryListener(new Mock<IDisposer<SharedMemoryListener>>().Object,
                                                   internallistener.Object, _ => null,
                                                   new Mock<IAsyncResultEnder<SharedMemoryStream>>().Object, null)
                              {
                                  WaitForTimeout = (int) timespan.TotalMilliseconds
                              };
            listener.BeginWaitFor(null, null);

            internallistener.Verify(l => l.WaitFor(It.Is<TimeSpan>(t => t == timespan)));
        }

        [Test(Description = "Checks that ending a wait for operation delegates to the async result ender.")]
        public void EndWaitFor_DelegatesToAsyncResultEnder()
        {
            var ender = new Mock<IAsyncResultEnder>();
            var task = Task.Factory.StartNew(() => { });

            var listener = new SharedMemoryListener(new Mock<IDisposer<SharedMemoryListener>>().Object,
                                                    null, null, null, ender.Object);
            listener.EndWaitFor(task);

            ender.Verify(e => e.EndTask(It.Is<IAsyncResult>(r => r == task),
                                        It.IsAny<Func<AggregateException, Exception>>()),
                         "Ending a wait for operation did not delegate to the async result ender.");
        }

    }
}